package wci.frontend.pascal.parsers;

import java.util.ArrayList;
import java.util.EnumSet;

import wci.frontend.*;
import wci.frontend.pascal.*;
import wci.intermediate.*;
import wci.intermediate.symtabimpl.*;
import wci.intermediate.typeimpl.*;

import static wci.frontend.pascal.PascalTokenType.*;
import static wci.frontend.pascal.PascalErrorCode.*;
import static wci.intermediate.symtabimpl.SymTabKeyImpl.*;
import static wci.intermediate.symtabimpl.DefinitionImpl.*;
import static wci.intermediate.symtabimpl.RoutineCodeImpl.*;

/**
 * <h1>DeclaredRoutineParser</h1>
 * <p>解析程式(过程和函数)，包括入口主程序</p>
 * <p>Copyright (c) 2009 by Ronald Mak</p>
 * <p>For instructional purposes only.  No warranties.</p>
 */
public class DeclaredRoutineParser extends DeclarationsParser
{
    public DeclaredRoutineParser(PascalParserTD parent)
    {
        super(parent);
    }
    // 程式名字计数器，在解析过程中可能有些程式忘记写名字了，为了不影响解析的进行，
    //需要纠错补上一个模拟名字，以数字代替
    private static int dummyCounter = 0;  

    /**
     * 解析一个标准的子程式声明
     * @param token 初始的token
     * @param parentId 父程式对应的符号表项
     * @return 声明程式对应的符号项
     * @throws Exception if an error occurred.
     */
    public SymTabEntry parse(Token token, SymTabEntry parentId)
        throws Exception
    {
        Definition routineDefn = null;
        String dummyName = null;
        SymTabEntry routineId = null;
        TokenType routineType = token.getType();

        //判断倒是何种程式
        switch ((PascalTokenType) routineType) {

            case PROGRAM: { //程序
                token = nextToken(); 
                routineDefn = DefinitionImpl.PROGRAM;
                dummyName = "DummyProgramName".toLowerCase();
                break;
            }

            case PROCEDURE: {//过程
                token = nextToken(); 
                routineDefn = DefinitionImpl.PROCEDURE;
                dummyName = "DummyProcedureName_".toLowerCase() +
                            String.format("%03d", ++dummyCounter);
                break;
            }

            case FUNCTION: {//函数
                token = nextToken(); 
                routineDefn = DefinitionImpl.FUNCTION;
                dummyName = "DummyFunctionName_".toLowerCase() +
                            String.format("%03d", ++dummyCounter);
                break;
            }

            default: {
                routineDefn = DefinitionImpl.PROGRAM;
                dummyName = "DummyProgramName".toLowerCase();
                break;
            }
        }

        // 解析程式的名称
        routineId = parseRoutineName(token, dummyName);
        routineId.setDefinition(routineDefn);

        token = currentToken();

        //创建此程式的中间码
        ICode iCode = ICodeFactory.createICode();
        routineId.setAttribute(ROUTINE_ICODE, iCode);
        routineId.setAttribute(ROUTINE_ROUTINES, new ArrayList<SymTabEntry>());

        // 判断程式是否前向来决定是否创建符号表
        if (routineId.getAttribute(ROUTINE_CODE) == FORWARD) {
            SymTab symTab = (SymTab) routineId.getAttribute(ROUTINE_SYMTAB);
            symTabStack.push(symTab);
        }
        else {
            routineId.setAttribute(ROUTINE_SYMTAB, symTabStack.push());
        }

        // 如果是程序，设置堆栈的程序ID
        if (routineDefn == DefinitionImpl.PROGRAM) {
            symTabStack.setProgramId(routineId);
        }else if (routineId.getAttribute(ROUTINE_CODE) != FORWARD) {
        	//对于非前向程式申明，将其放入到父程式的子程式列表中
            ArrayList<SymTabEntry> subroutines = (ArrayList<SymTabEntry>)
                                       parentId.getAttribute(ROUTINE_ROUTINES);
            subroutines.add(routineId);
        }

        //如果这个是已经前向申明过后“定义”，不能有任何参数和返回值，应该是分号;
        if (routineId.getAttribute(ROUTINE_CODE) == FORWARD) {
            if (token.getType() != SEMICOLON) {
                errorHandler.flag(token, ALREADY_FORWARDED, this);
                parseHeader(token, routineId);
            }
        }else { //正常（非前向）的解析程式头（参数+返回式）
            parseHeader(token, routineId);
        }

        // 头完之后是否是分号
        token = currentToken();
        if (token.getType() == SEMICOLON) {
            do {
                token = nextToken();
            } while (token.getType() == SEMICOLON);
        }
        else {
            errorHandler.flag(token, MISSING_SEMICOLON, this);
        }

        //解析之后的块或者代替的forward
        if ((token.getType() == IDENTIFIER) &&
            (token.getText().equalsIgnoreCase("forward")))
        {
        	//是一个前向申明
            token = nextToken(); 
            routineId.setAttribute(ROUTINE_CODE, FORWARD);
        }else { //正常的调用块解析
            routineId.setAttribute(ROUTINE_CODE, DECLARED);
            BlockParser blockParser = new BlockParser(this);
            ICodeNode rootNode = blockParser.parse(token, routineId);
            iCode.setRoot(rootNode);
        }

        // 程式的作用域结束，出栈
        symTabStack.pop();

        return routineId;
    }

    /**
     * 解析程式的名字
     * @param token 当前token
     * @param dummyName 解析出问题时的假名字
     * @return 申明的程式名字对应的符号表项
     * @throws Exception
     */
    private SymTabEntry parseRoutineName(Token token, String dummyName)
        throws Exception
    {
        SymTabEntry routineId = null;

        //解析程式名称标识符
        if (token.getType() == IDENTIFIER) {
            String routineName = token.getText().toLowerCase();
            routineId = symTabStack.lookupLocal(routineName);

            // 如果没有定义，放到符号表中
            if (routineId == null) {
                routineId = symTabStack.enterLocal(routineName);
            }

            // 如果已经被定义，则判断是否一个前向申明
            else if (routineId.getAttribute(ROUTINE_CODE) != FORWARD) {
                routineId = null;
                errorHandler.flag(token, IDENTIFIER_REDEFINED, this);
            }

            token = nextToken(); 
        }
        else { //忘记写名字了
            errorHandler.flag(token, MISSING_IDENTIFIER, this);
        }

        //如果routineID没有名字，放个假名字代替
        if (routineId == null) {
            routineId = symTabStack.enterLocal(dummyName);
        }

        return routineId;
    }

    /**
     * 解析程式的头，包括参数列表和返回
     * @param token 当前Token
     * @param routineId 申明过程式名称对应的符号表项
     * @throws Exception
     */
    private void parseHeader(Token token, SymTabEntry routineId)
        throws Exception
    {
        //先解析形参列表
        parseFormalParameters(token, routineId);
        token = currentToken();

        // 如果程式是函数，则要解析它的返回值类型function p : int
        if (routineId.getDefinition() == DefinitionImpl.FUNCTION) {
            VariableDeclarationsParser variableDeclarationsParser =
                new VariableDeclarationsParser(this);
            variableDeclarationsParser.setDefinition(DefinitionImpl.FUNCTION);
            TypeSpec type = variableDeclarationsParser.parseTypeSpec(token);

            token = currentToken();

            // 返回值类型不能是数组或者记录，只能是标量类型
            if (type != null) {
                TypeForm form = type.getForm();
                if ((form == TypeFormImpl.ARRAY) ||
                    (form == TypeFormImpl.RECORD))
                {
                    errorHandler.flag(token, INVALID_TYPE, this);
                }
            } else { //函数漏掉了返回类型
                type = Predefined.undefinedType;
            }

            routineId.setTypeSpec(type);
            token = currentToken();
        }
    }

    // 形参子表的同步集
    private static final EnumSet<PascalTokenType> PARAMETER_SET =
        DeclarationsParser.DECLARATION_START_SET.clone();
    static {
        PARAMETER_SET.add(VAR);
        PARAMETER_SET.add(IDENTIFIER);
        PARAMETER_SET.add(RIGHT_PAREN);
    }

    //左括号处的同步集
    private static final EnumSet<PascalTokenType> LEFT_PAREN_SET =
        DeclarationsParser.DECLARATION_START_SET.clone();
    static {
        LEFT_PAREN_SET.add(LEFT_PAREN);
        LEFT_PAREN_SET.add(SEMICOLON);
        LEFT_PAREN_SET.add(COLON);
    }

    //右括号的同步集
    private static final EnumSet<PascalTokenType> RIGHT_PAREN_SET =
        LEFT_PAREN_SET.clone();
    static {
        RIGHT_PAREN_SET.remove(LEFT_PAREN);
        RIGHT_PAREN_SET.add(RIGHT_PAREN);
    }

    /**
     * 解析程式的形参列表
     * @param token 当前token
     * @param routineId 程式名称对应的符号表项
     * @throws Exception
     */
    protected void parseFormalParameters(Token token, SymTabEntry routineId)
        throws Exception
    {
        // 同步左括号集
        token = synchronize(LEFT_PAREN_SET);
        if (token.getType() == LEFT_PAREN) {//必须得是一个左括号
            token = nextToken(); 
            ArrayList<SymTabEntry> parms = new ArrayList<SymTabEntry>();
            token = synchronize(PARAMETER_SET);
            TokenType tokenType = token.getType();

            // 遍历解析形参子表，注意参数前面加VAR表示引用传递
            while ((tokenType == IDENTIFIER) || (tokenType == VAR)) {
                parms.addAll(parseParmSublist(token, routineId));
                token = currentToken();
                tokenType = token.getType();
            }

            // 参数结束的右括号
            if (token.getType() == RIGHT_PAREN) {
                token = nextToken();  // consume )
            }
            else {
                errorHandler.flag(token, MISSING_RIGHT_PAREN, this);
            }

            routineId.setAttribute(ROUTINE_PARMS, parms);
        }
    }

    // 一个形参后的同步集
    private static final EnumSet<PascalTokenType> PARAMETER_FOLLOW_SET =
        EnumSet.of(COLON, RIGHT_PAREN, SEMICOLON);
    static {
        PARAMETER_FOLLOW_SET.addAll(DeclarationsParser.DECLARATION_START_SET);
    }

    // 逗号处的同步集
    private static final EnumSet<PascalTokenType> COMMA_SET =
        EnumSet.of(COMMA, COLON, IDENTIFIER, RIGHT_PAREN, SEMICOLON);
    static {
        COMMA_SET.addAll(DeclarationsParser.DECLARATION_START_SET);
    }

    /**
     * 解析形参子表，每个以分号隔开的为一个子表
     * @param token 当前Token
     * @param routineId 程式名称对应的符号表项
     * @return 子表对应的符号表项
     * @throws Exception
     */
    private ArrayList<SymTabEntry> parseParmSublist(Token token,
                                                    SymTabEntry routineId)
        throws Exception
    {
        boolean isProgram = routineId.getDefinition() == DefinitionImpl.PROGRAM;
        Definition parmDefn = isProgram ? PROGRAM_PARM : null;
        TokenType tokenType = token.getType();

        // 引用或值传递？
        if (tokenType == VAR) {
            if (!isProgram) {
                parmDefn = VAR_PARM;
            }
            else {
                errorHandler.flag(token, INVALID_VAR_PARM, this);
            }

            token = nextToken();  // consume VAR
        }
        else if (!isProgram) {
            parmDefn = VALUE_PARM;
        }

        // 解析参数子表及它的类型
        VariableDeclarationsParser variableDeclarationsParser =
            new VariableDeclarationsParser(this);
        variableDeclarationsParser.setDefinition(parmDefn);
        ArrayList<SymTabEntry> sublist =
            variableDeclarationsParser.parseIdentifierSublist(
                                           token, PARAMETER_FOLLOW_SET,
                                           COMMA_SET);
        token = currentToken();
        tokenType = token.getType();

        if (!isProgram) {

            // 搜寻并吞噬一个子表后的分号
            if (tokenType == SEMICOLON) {
                while (token.getType() == SEMICOLON) {
                    token = nextToken();  // consume the ;
                }
            } else if (VariableDeclarationsParser.NEXT_START_SET.contains(tokenType)) {
                errorHandler.flag(token, MISSING_SEMICOLON, this);
            }

            token = synchronize(PARAMETER_SET);
        }

        return sublist;
    }
}
